Skip to content

S01-06 JavaSE-数组

[TOC]

概述

为什么需要数组

一个养鸡场有 6 只鸡,它们的体重分别是 3kg、5kg、1kg、3.4kg、2kg、50kg 。请问这六只鸡的总体重是多少?平均体重是多少?请你编一个程序(Array01.java)

思路:定义 6 个变量,加起来求总体重,进而求出平均体重。引出-> 数组

数组介绍

数组:是一种引用数据类型,用于存储固定长度相同数据类型的元素集合。它将多个同类型的变量按连续的内存地址组织起来,通过 下标(索引) 快速访问每个元素,是处理批量同类型数据的基础结构。

即:数(数据)组(一组)就是一组数据

快速入门:养鸡场

比如,我们可以用数组来解决上一个问题,体验数组的使用:

java
public class Array01 {
    //编写一个main方法
    public static void main(String[] args) {
        /*
        它们的体重分别是3kg,5kg,1kg,3.4kg,2kg,50kg 。
        请问这六只鸡的总体重是多少?平均体重是多少?
        思路分析
        1. 定义六个变量double , 求和得到总体重
        2. 平均体重= 总体重/ 6
        3. 分析传统实现的方式问题:6->600->566
        4. 引出新的技术-> 使用数组来解决.
        */
        // 传统方式实现(注释掉,用于对比)
        // double hen1 = 3;
        // double hen2 = 5;
        // double hen3 = 1;
        // double hen4 = 3.4;
        // double hen5 = 2;
        // double hen6 = 50;
        // double totalWeight = hen1 + hen2 + hen3 + hen4 + hen5 + hen6;
        // double avgWeight = totalWeight / 6;
        // System.out.println("总体重=" + totalWeight + " 平均体重=" + avgWeight);

        // 用数组解决
        // 老韩解读
        // 1. double[] 表示是double类型的数组,数组名hens
        // 2. {3, 5, 1, 3.4, 2, 50, 7.8, 88.8, 1.1, 5.6, 100} 表示数组的值/元素,依次对应数组的各个元素
        double[] hens = {3, 5, 1, 3.4, 2, 50, 7.8, 88.8, 1.1, 5.6, 100};

        System.out.println("===使用数组解决===");
        // 老师提示:可以通过数组名.length 得到数组的大小/长度
        // System.out.println("数组的长度=" + hens.length);

        double totalWeight = 0;
        // 遍历数组得到所有元素的和
        // 老韩解读
        // 1. 可以通过hens[下标] 访问数组的元素,下标从0开始(第一个元素hens[0],第二个hens[1],依次类推)
        // 2. 通过for循环访问数组的所有元素
        // 3. 使用变量totalWeight累积各个元素的值
        for (int i = 0; i < hens.length; i++) {
            // System.out.println("第" + (i+1) + "个元素的值=" + hens[i]);
            totalWeight += hens[i];
        }

        System.out.println("总体重=" + totalWeight + " 平均体重=" + (totalWeight / hens.length));
    }
}

数组基础

数组初始化

方式 1:动态初始化-声明时赋值

语法

java
// 语法
数据类型 数组名[] = new 数据类型[大小]

// 示例:
int a[] = new int[5]; // 创建了一个int类型数组,名字a,可存放5个int值

说明:这是定义数组的一种方法,结合数组内存图理解

image-20251216164223913

示例:快速入门

循环输入 5 个成绩,保存到 double 数组,并输出:

java
import java.util.Scanner;

public class Array02 {
    public static void main(String[] args) {
        // 演示动态初始化数组
        // 循环输入5个成绩,保存到double数组,并输出

        // 步骤
        // 1. 创建double数组,大小5
        // (1) 第一种动态分配方式:double scores[] = new double[5];
        // (2) 第二种动态分配方式:先声明数组,再分配内存空间
        double scores[]; // 声明数组,此时scores是null
        scores = new double[5]; // 分配内存空间,可存放5个double数据

        // 2. 循环输入成绩
        Scanner myScanner = new Scanner(System.in);
        for (int i = 0; i < scores.length; i++) {
            System.out.println("请输入第" + (i+1) + "个成绩:");
            scores[i] = myScanner.nextDouble();
        }

        // 3. 输出数组元素
        System.out.println("==数组的元素/值的情况如下:===");
        for (int i = 0; i < scores.length; i++) {
            System.out.println("第" + (i+1) + "个元素的值=" + scores[i]);
        }
    }
}

方式 2:动态初始化-先声明再赋值

  1. 声明数组

    java
    // 语法
    数据类型 数组名[];
    数据类型[] 数组名;
    
    // 示例
    int a[];
    int[] a;
  2. 创建数组(分配内存)

    java
    // 语法
    数组名 = new 数据类型[大小];
    
    // 示例
    a = new int[10];

案例演示:基于前面的代码修改即可

方式 3:静态初始化

语法

如果已知数组的元素个数和具体值,可直接使用静态初始化。

等价于:先创建指定大小的数组,再逐个给元素赋值。

java
数据类型 数组名[] = {元素值1, 元素值2, ..., 元素值n};

示例

java
// 静态初始化
int a[] = {2,5,6,7,8,89,90,34,56};

// 等价于动态初始化的如下写法
int a[] = new int[9];
a[0] = 2; a[1] = 5; a[2] = 6; a[3] = 7; a[4] = 8;
a[5] = 89; a[6] = 90; a[7] = 34; a[8] = 56;

// 养鸡场案例中的数组(静态初始化)
double hens[] = {3, 5, 1, 3.4, 2, 50};
// 等价于
double hens[] = new double[6];
hens[0] = 3; hens[1] = 5; hens[2] = 1; hens[3] = 3.4; hens[4] = 2; hens[5] = 50;

数组的访问

语法

java
// 语法
数组名[下标/索引/index]

// 示例:
a[2] // 访问a数组的第3个元素,数组下标从0开始

数组核心特性

  1. 数组是多个相同类型数据的组合,实现对这些数据的统一管理。

  2. 数组中的元素可以是任何数据类型(包括基本类型和引用类型),但不能混用

  3. 数组创建后如果没有赋值,会有默认值:

    • 基本类型:
      • int 0short 0byte 0long 0
      • float 0.0double 0.0
      • char \u0000
      • ``boolean false`
    • 引用类型(如 String):null
  4. 使用数组的步骤:

    1. 声明数组并开辟空间
    2. 给数组元素赋值
    3. 使用数组
  5. 数组的下标从0开始。

  6. 数组下标必须在指定范围内使用(有效范围:0 ~ length-1),否则报下标越界异常

    java
    // 有效下标为0-4,访问 arr[5] 会报错
    int[] arr = new int[5];
  7. 数组属于引用类型,数组型数据是对象(object)。


示例:验证代码

java
public class ArrayDetail {
    //编写一个main方法
    public static void main(String[] args) {
        // 1. 数组元素类型必须相同(错误示例:int数组中不能放String)
        // int[] arr1 = {1, 2, 3, 60, "hello"}; // 编译错误:String无法转换为int
        double[] arr2 = {1.1, 2.2, 3.3, 60.6, 100}; // 正确:int自动转换为double

        // 2. 数组元素可以是引用类型(示例:String数组)
        String[] arr3 = {"北京", "jack", "milan"};

        // 3. 数组未赋值时的默认值
        short[] arr4 = new short[3];
        System.out.println("=====数组arr4(未赋值的默认值)=====");
        for (int i = 0; i < arr4.length; i++) {
            System.out.println(arr4[i]); // 输出3个0(short类型默认值)
        }

        // 6. 数组下标越界演示(注释掉,避免运行报错)
        // int[] arr = new int[5];
        // System.out.println(arr[5]); // 运行时异常:ArrayIndexOutOfBoundsException
    }
}

数组应用

应用 1:创建 26 个字母数组

创建一个 char 类型的 26 个元素的数组,分别放置'A'-'Z',使用 for 循环访问所有元素并打印。

提示:char 类型支持运算('A' + 2 → 'C'

java
public class ArrayExercise01 {
    public static void main(String[] args) {
        /*
        思路分析
        1. 定义char数组,大小26
        2. 利用'A' + i 的运算赋值(i从0到25)
        3. 循环访问并打印所有元素
        */
        char[] chars = new char[26];
        // 赋值:A~Z
        for (int i = 0; i < chars.length; i++) {
            // 'A' + i 是int类型,需要强制转换为char
            chars[i] = (char) ('A' + i);
        }
        // 输出
        System.out.println("===chars数组===");
        for (int i = 0; i < chars.length; i++) {
            System.out.print(chars[i] + " "); // 输出:A B C ... Z
        }
    }
}

应用 2:求数组最大值及下标

请求出数组int[] arr = {4, -1, 9, 10, 23}的最大值,并得到对应的下标。

java
public class ArrayExercise02 {
    //编写一个main方法
    public static void main(String[] args) {
        /*
        老韩思路分析
        1. 定义目标数组
        2. 假定第一个元素为最大值(max = arr[0]),下标为maxIndex=0
        3. 从下标1开始遍历数组,若当前元素>max,则更新max和maxIndex
        4. 遍历结束后,max即为最大值,maxIndex为对应下标
        */
        int[] arr = {4, -1, 9, 10, 23};
        int max = arr[0]; // 假定第一个元素是最大值
        int maxIndex = 0; // 最大值的初始下标

        // 从下标1开始遍历
        for (int i = 1; i < arr.length; i++) {
            if (max < arr[i]) { // 若当前元素大于max
                max = arr[i]; // 更新最大值
                maxIndex = i; // 更新最大值下标
            }
        }

        System.out.println("max=" + max + " maxIndex=" + maxIndex); // 输出:max=23 maxIndex=4
    }
}

应用 3:求数组的和和平均值

基于养鸡场案例,直接通过数组遍历求和,再计算平均值(已在 Array01.java 中实现)。

数组操作

数组赋值机制

基本类型赋值

赋值的是具体的数据,两个变量相互独立,修改一个不影响另一个。

java
int n1 = 2;
int n2 = n1;
n2 = 80;
System.out.println("n1=" + n1); // 输出10(不受n2修改影响)
System.out.println("n2=" + n2); // 输出80

引用赋值

数组默认是引用传递,赋值的是数组的地址,两个数组变量指向同一个内存空间。

修改其中一个数组的元素,会影响另一个数组。


示例

java
public class ArrayAssign {
    public static void main(String[] args) {
        int[] arr1 = {1, 2, 3};
        int[] arr2 = arr1; // 引用传递:arr2指向arr1的内存地址

        arr2[0] = 10; // 修改arr2的元素

        // 输出arr1和arr2的元素
        System.out.println("====arr1的元素====");
        for (int i = 0; i < arr1.length; i++) {
            System.out.println(arr1[i]); // 输出:10, 2, 3(arr1的元素被修改)
        }
        System.out.println("====arr2的元素====");
        for (int i = 0; i < arr2.length; i++) {
            System.out.println(arr2[i]); // 输出:10, 2, 3
        }
    }
}

内存解析

  • 栈内存:存储变量(arr1、arr2),保存数组的内存地址(如 0x0011)。
  • 堆内存:存储数组的实际元素(1,2,3),地址为 0x0011。
  • arr1 和 arr2 都指向 0x0011,修改 arr2[0]本质是修改堆内存中数组的元素。

image-20251216164932336

数组拷贝

要求:实现数组内容的复制,新数组与原数组的数据空间独立(修改新数组不影响原数组)。

java
public class ArrayCopy {
    //编写一个main方法
    public static void main(String[] args) {
        // 原数组
        int[] arr1 = {10, 20, 30};

        // 1. 创建新数组,开辟独立的内存空间(大小与原数组一致)
        int[] arr2 = new int[arr1.length];

        // 2. 遍历原数组,将元素逐个拷贝到新数组
        for (int i = 0; i < arr1.length; i++) {
            arr2[i] = arr1[i];
        }

        // 修改新数组的元素(验证独立性)
        arr2[0] = 100;

        // 输出原数组(不受影响)
        System.out.println("====arr1的元素====");
        for (int i = 0; i < arr1.length; i++) {
            System.out.println(arr1[i]); // 输出:10, 20, 30
        }

        // 输出新数组(已修改)
        System.out.println("====arr2的元素====");
        for (int i = 0; i < arr2.length; i++) {
            System.out.println(arr2[i]); // 输出:100, 20, 30
        }
    }
}

数组反转

要求:将数组元素反转(如{11,22,33,44,55,66}{66,55,44,33,22,11}

方式 1:原地反转

思路分析

  1. 交换规律:arr[i]arr[arr.length - 1 - i] 交换(i 从 0 开始)。
  2. 交换次数:arr.length / 2(如 6 个元素交换 3 次,5 个元素交换 2 次)。

代码实现

java
public class ArrayReverse {
    public static void main(String[] args) {
        int[] arr = {11, 22, 33, 44, 55, 66};
        int temp = 0; // 辅助交换的临时变量
        int len = arr.length; // 数组长度(优化:避免重复计算)

        // 交换逻辑
        for (int i = 0; i < len / 2; i++) {
            temp = arr[len - 1 - i]; // 保存末尾元素
            arr[len - 1 - i] = arr[i]; // 前面元素移到末尾
            arr[i] = temp; // 末尾元素移到前面
        }

        // 输出反转后的数组
        System.out.println("===翻转后数组===");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + "\t"); // 输出:66	55	44	33	22	11
        }
    }
}

方式 2:逆序赋值

思路分析

  1. 创建与原数组大小相同的新数组arr2
  2. 逆序遍历原数组,将元素依次赋值给新数组的正序位置。
  3. 让原数组变量arr指向新数组(原数组内存空间变为垃圾,被 JVM 回收)。

image-20251216165041752

代码实现

java
public class ArrayReverse02 {
    public static void main(String[] args) {
        int[] arr = {11, 22, 33, 44, 55, 66};
        // 创建新数组
        int[] arr2 = new int[arr.length];

        // 逆序遍历原数组,赋值给新数组
        for (int i = arr.length - 1, j = 0; i >= 0; i--, j++) {
            arr2[j] = arr[i];
        }

        // 原数组变量指向新数组
        arr = arr2;

        // 输出结果
        System.out.println("====arr的元素情况=====");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + "\t"); // 输出:66	55	44	33	22	11
        }
    }
}

数组扩容

要求:实现动态给数组添加元素,支持用户自主选择是否继续添加(ArrayAdd02.java)

需求

  1. 原始数组:int[] arr = {1,2,3}(静态分配)。
  2. 每次添加元素到数组末尾(如添加 4 → {1,2,3,4})。
  3. 提示用户输入添加的元素,添加成功后询问是否继续(y/n)。

思路分析

  1. 每次添加时,创建新数组(大小=原数组长度+1)。
  2. 将原数组元素拷贝到新数组。
  3. 新元素赋值给新数组的最后一个位置。
  4. 原数组变量指向新数组(完成扩容)。
  5. 使用do-while循环+break控制用户输入逻辑。

代码实现

java
import java.util.Scanner;

public class ArrayAdd02 {
    public static void main(String[] args) {
        Scanner myScanner = new Scanner(System.in);
        // 初始化原数组
        int[] arr = {1, 2, 3};

        do {
            // 1. 创建新数组(扩容+1)
            int[] arrNew = new int[arr.length + 1];
            // 2. 拷贝原数组元素到新数组
            for (int i = 0; i < arr.length; i++) {
                arrNew[i] = arr[i];
            }

            // 3. 接收用户输入的新元素
            System.out.println("请输入你要添加的元素:");
            int addNum = myScanner.nextInt();
            // 4. 新元素放入新数组末尾
            arrNew[arrNew.length - 1] = addNum;
            // 5. 原数组指向新数组
            arr = arrNew;

            // 输出扩容后的数组
            System.out.println("====arr扩容后元素情况====");
            for (int i = 0; i < arr.length; i++) {
                System.out.print(arr[i] + "\t");
            }

            // 询问用户是否继续
            System.out.println("\n是否继续添加?y/n");
            char key = myScanner.next().charAt(0);
            if (key == 'n') { // 输入n则退出
                break;
            }
        } while (true); // 无限循环,直到用户输入n

        System.out.println("你退出了添加...");
    }
}

练习:数组缩减

需求:有一个数组{1,2,3,4,5},提示用户是否继续缩减,每次缩减最后一个元素。当只剩最后一个元素时,提示“不能再缩减”。

image-20251216165144848

算法

排序

排序介绍

排序是将多个数据按指定顺序排列的过程。

排序分类

  1. 内部排序:所有数据加载到内部存储器(内存)中排序,包括:
    • 交换式排序法(如冒泡排序)
    • 选择式排序法
    • 插入式排序法
  2. 外部排序法:数据量过大,无法全部加载到内存,需借助外部存储(如硬盘)排序,包括:
    • 合并排序法
    • 直接合并排序法

冒泡排序

冒泡排序(Bubble Sorting):通过对待排序序列从后向前(下标较大的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部(类似气泡上浮)。

案例:冒泡排序实现

将无序数组{24,69,80,57,13}排成从小到大的有序数列。

思路分析

  1. n 个元素需进行 n-1 轮排序(外层循环次数)。
  2. 每轮排序确定一个元素的最终位置(从最大到最小依次归位)。
  3. 每轮比较次数 = 数组长度 - 1 - 当前轮数(内层循环次数)。
  4. 核心逻辑:相邻元素逆序则交换。

实现步骤

数组初始状态:[24,69,80,57,13]

  • 第 1 轮排序(目标:最大数 80 移到末尾):
    • 比较 24&69(不交换)→ 69&80(不交换)→ 80&57(交换 →[24,69,57,80,13])→ 80&13(交换 →[24,69,57,13,80])
  • 第 2 轮排序(目标:第二大数 69 移到倒数第二):
    • 比较 24&69(不交换)→ 69&57(交换 →[24,57,69,13,80])→ 69&13(交换 →[24,57,13,69,80])
  • 第 3 轮排序(目标:第三大数 57 移到倒数第三):
    • 比较 24&57(不交换)→ 57&13(交换 →[24,13,57,69,80])
  • 第 4 轮排序(目标:第四大数 24 移到倒数第四):
    • 比较 24&13(交换 →[13,24,57,69,80])

image-20251216165414531

代码实现

java
public class BubbleSort {
    public static void main(String[] args) {
        int[] arr = {24, 69, 80, 57, 13, -1, 30, 200, -110};
        int temp = 0; // 辅助交换的变量

        // 外层循环:控制排序轮数(n个元素需n-1轮)
        for (int i = 0; i < arr.length - 1; i++) {
            // 内层循环:每轮比较次数(每轮减少1次,因为末尾已排好序)
            for (int j = 0; j < arr.length - 1 - i; j++) {
                // 相邻元素比较,逆序则交换(从小到大排序)
                if (arr[j] > arr[j + 1]) {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }

            // 输出每轮排序结果
            System.out.println("\n==第" + (i+1) + "轮==");
            for (int j = 0; j < arr.length; j++) {
                System.out.print(arr[j] + "\t");
            }
        }
    }
}

查找

在 Java 中,常用的查找方式有两种:

  1. 顺序查找(本章重点)
  2. 二分查找(后续算法讲解)

顺序查找

需求:有一个数列:{"白眉鹰王", "金毛狮王", "紫衫龙王", "青翼蝠王"},从键盘输入一个名称,判断数列中是否包含该名称。若找到,提示找到并给出下标;若未找到,提示未找到。

思路分析

  1. 定义字符串数组存储目标数列。
  2. 接收用户输入的查找名称。
  3. 遍历数组,逐一比较(字符串比较用equals方法)。
  4. 用变量index标记找到的下标(初始值-1,未找到则保持-1)。

代码实现

java
import java.util.Scanner;

public class SeqSearch {
    public static void main(String[] args) {
        // 目标数组
        String[] names = {"白眉鹰王", "金毛狮王", "紫衫龙王", "青翼蝠王"};
        Scanner myScanner = new Scanner(System.in);

        System.out.println("请输入名字:");
        String findName = myScanner.next();

        // 查找逻辑
        int index = -1; // 标记下标(未找到为-1)
        for (int i = 0; i < names.length; i++) {
            // 比较输入名称与数组元素
            if (findName.equals(names[i])) {
                System.out.println("恭喜你找到" + findName);
                System.out.println("下标为= " + i);
                index = i; // 更新下标
                break; // 找到后退出循环
            }
        }

        // 未找到的提示
        if (index == -1) {
            System.out.println("sorry,没有找到" + findName);
        }
    }
}

二分查找(有序数组)

需求:对有序数组{1,8,10,89,1000,1234},输入一个数,判断是否存在并求出下标(二分查找效率高于顺序查找)。

二维数组

多维数组中最常用的是二维数组,应用场景如:五子棋棋盘(行列坐标)、表格数据等。

快速入门

需求:用二维数组输出如下图形:

0 0 0 0 0 0
0 0 1 0 0 0
0 2 0 3 0 0
0 0 0 0 0 0

代码实现

java
public class TwoDimensionalArray01 {
    public static void main(String[] args) {
        /*
        二维数组定义:
        1. 从形式上看:int[][] 表示二维数组(一维数组的每个元素是一维数组)
        2. 初始化:{ {0,0,0,0,0,0}, {0,0,1,0,0,0}, {0,2,0,3,0,0}, {0,0,0,0,0,0} }
        */
        int[][] arr = {
                {0, 0, 0, 0, 0, 0},
                {0, 0, 1, 0, 0, 0},
                {0, 2, 0, 3, 0, 0},
                {0, 0, 0, 0, 0, 0}
        };

        // 二维数组的关键概念
        System.out.println("二维数组的元素个数(一维数组的个数)=" + arr.length); // 输出4(4个一维数组)
        // 访问指定元素:第3个一维数组的第4个值(arr[2][3],下标从0开始)
        System.out.println("第3个一维数组的第4个值=" + arr[2][3]); // 输出3

        // 遍历二维数组(嵌套循环)
        System.out.println("===二维数组图形输出===");
        for (int i = 0; i < arr.length; i++) { // 遍历二维数组的每个一维数组
            for (int j = 0; j < arr[i].length; j++) { // 遍历当前一维数组的每个元素
                System.out.print(arr[i][j] + " ");
            }
            System.out.println(); // 换行
        }
    }
}

初始化

方式 1:动态初始化-固定行列

语法

java
类型[][] 数组名 = new 类型[行数][列数]

示例

java
public class TwoDimensionalArray02 {
    public static void main(String[] args) {
        // 方式1:直接初始化
        // int[][] arr = new int[2][3]; // 2行3列的二维数组

        // 方式2:先声明,再分配空间
        int[][] arr;
        arr = new int[2][3]; // 2个一维数组,每个一维数组有3个元素
        arr[1][1] = 8; // 给第2行第2列的元素赋值8

        // 遍历二维数组
        System.out.println("===二维数组输出===");
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                System.out.print(arr[i][j] + " ");
            }
            System.out.println();
        }
    }
}

内存解析

  • 栈内存arr 存储二维数组的地址(如 0x0011)。
  • 堆内存
    • 二维数组(地址 0x0011)存储两个一维数组的地址(如 0x0022、0x0033)。
    • 一维数组(0x0022):[0,0,0](默认值)。
    • 一维数组(0x0033):[0,8,0](arr[1][1]赋值为 8)。

image-20251216165917783

方式 3:动态初始化-列数不确定

需求:动态创建如下二维数组(每行列数不同),并输出:

i=0: 1
i=1: 2 2
i=2: 3 3 3

思路分析

  1. 创建二维数组时,只指定行数(3 行),不指定列数。
  2. 遍历每行,为每行的一维数组分配不同的列数(第 i 行分配 i+1 列)。
  3. 给每行的元素赋值(第 i 行的元素值为 i+1)。

代码实现

java
public class TwoDimensionalArray03 {
    public static void main(String[] args) {
        // 创建二维数组(3行,列数不确定)
        int[][] arr = new int[3][];

        // 为每行分配列数并赋值
        for (int i = 0; i < arr.length; i++) {
            arr[i] = new int[i + 1]; // 第i行分配i+1列(0行1列,1行2列,2行3列)
            // 给当前行的元素赋值
            for (int j = 0; j < arr[i].length; j++) {
                arr[i][j] = i + 1; // 元素值为行号+1
            }
        }

        // 输出二维数组
        System.out.println("=====arr元素=====");
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                System.out.print(arr[i][j] + " ");
            }
            System.out.println(); // 换行
        }
    }
}

方式 4:静态初始化

语法

java
类型[][] 数组名 = { {值1,值2,...}, {值1,值2,...}, ... }

示例

java
// 静态初始化二维数组(3行,列数分别为3、3、1)
int[][] arr = { {1,1,1}, {8,8,9}, {100} };

解读

  • 二维数组arr有 3 个元素(每个元素是一维数组)。
  • 第一个一维数组:[1, 1, 1](3 个元素)。
  • 第二个一维数组:[8, 8, 9](3 个元素)。
  • 第三个一维数组:[100](1 个元素)。

案例:二维数组求和

需求

遍历二维数组int arr[][] = { {4,6}, {1,4,5,7}, {-2} },计算所有元素的和。

代码实现

java
public class TwoDimensionalArray05 {
    public static void main(String[] args) {
        int arr[][] = { {4,6}, {1,4,5,7}, {-2} };
        int sum = 0; // 累积和

        // 嵌套循环遍历二维数组
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                sum += arr[i][j]; // 累加每个元素
            }
        }

        System.out.println("sum=" + sum); // 输出:4+6+1+4+5+7+(-2) = 25
    }
}

案例:打印杨辉三角

杨辉三角规律

  1. 第 1 行有 1 个元素,第 n 行有 n 个元素。
  2. 每行的第一个元素和最后一个元素都是 1。
  3. 从第 3 行开始,中间元素的值 = 上一行同列元素 + 上一行前一列元素(arr[i][j] = arr[i-1][j] + arr[i-1][j-1])。

代码实现:(打印 10 行杨辉三角)

java
public class YangHui {
    public static void main(String[] args) {
        int rows = 10; // 杨辉三角的行数
        int[][] yangHui = new int[rows][]; // 动态初始化二维数组(行数固定,列数不确定)

        // 给杨辉三角赋值
        for (int i = 0; i < yangHui.length; i++) {
            yangHui[i] = new int[i + 1]; // 第i行有i+1个元素
            // 给每行的第一个和最后一个元素赋值1
            yangHui[i][0] = 1;
            yangHui[i][i] = 1;
            // 给中间元素赋值(从第3行开始,i>=2)
            if (i >= 2) {
                for (int j = 1; j < yangHui[i].length - 1; j++) {
                    yangHui[i][j] = yangHui[i-1][j] + yangHui[i-1][j-1];
                }
            }
        }

        // 输出杨辉三角
        System.out.println("===杨辉三角(" + rows + "行)===");
        for (int i = 0; i < yangHui.length; i++) {
            for (int j = 0; j < yangHui[i].length; j++) {
                System.out.print(yangHui[i][j] + "\t");
            }
            System.out.println(); // 换行
        }
    }
}

二维数组注意事项

  1. 一维数组的声明方式int[] xint x[]

  2. 二维数组的声明方式int[][] yint[] y[]int y[][](三种都合法,推荐第一种)。

  3. 二维数组由多个一维数组组成,各个一维数组的长度可以不同(列数不等的二维数组)。

    java
    // map[0]有2个元素,map[1]有3个元素
    int map[][] = { {1,2}, {3,4,5} };

练习

声明int[] x, y[];,以下选项允许通过编译的是(BE)

  • a) x[0] = y; → 错误(int 类型不能接收 int[][]类型)
  • b) y[0] = x; → 正确(int[]类型接收 int[]类型)
  • c) y[0][0] = x; → 错误(int 类型不能接收 int[]类型)
  • d) x[0][0] = y; → 错误(x 是一维数组,x[0][0]语法错误)
  • e) y[0][0] = x[0]; → 正确(int 类型接收 int 类型)
  • f) x = y; → 错误(int[]类型不能接收 int[][]类型)

本章作业

  1. 下面数组定义正确的有(BD)

    • A. String strs[] = {'a','b','c'}; → 错误(字符串数组不能用 char 字面量初始化)
    • B. String[] strs = {"a","b","c"}; → 正确(静态初始化字符串数组)
    • C. String[] strs = new String{"a" "b" "c"}; → 错误(语法错误:缺少逗号和右括号)
    • D. String strs[] = new String[]{"a", "b","c"}; → 正确
    • E. String[] strs = new String[3]{"a", "b", "c"); → 错误(动态初始化指定长度后不能直接赋值元素)
  2. 写出结果

    java
    String foo = "blue";
    boolean[] bar = new boolean[2];
    if (bar[0]) {
        foo = "green";
    }
    System.out.println(foo); // 输出:blue(boolean数组默认值为false,if条件不成立)
  3. 以下 Java 代码的输出结果为()

    java
    int num = 1;
    while (num < 10) {
        System.out.println(num);
        if (num > 5) {
            break;
        }
        num += 2;
    }
    // 输出:1、3、5、7(num=1→3→5→7,7>5触发break)
  4. 有序数组插入元素:已知升序数组[10,12,45,90],插入元素23后保持升序(结果[10,12,23,45,90])。

    实现步骤

    1. 定义原数组和待插入元素:确定升序原数组和需要插入的元素。
    2. 查找插入位置:遍历原数组,找到第一个大于插入元素的位置(即为插入点);若元素比所有元素都大,则插入到数组末尾。
    3. 创建新数组:长度为原数组长度 + 1,用于存储插入后的结果。
    4. 复制元素并插入:将原数组中插入位置前的元素复制到新数组,放入插入元素,再复制插入位置后的元素。
    5. 验证结果:输出新数组,确认升序性。

    代码实现

    java
    // 1. 定义原升序数组和待插入的元素
    int[] arr = {10, 12, 45, 90};
    int insertNum = 23;
    
    // 2. 查找插入位置
    int insertIndex = -1;
    for (int i = 0; i < arr.length; i++) {
        // 找到第一个大于待插入元素的位置,即为插入点
        if (arr[i] > insertNum) {
            insertIndex = i;
            break;
        }
    }
    // 若元素比所有元素都大,插入到数组末尾
    if(insertIndex == -1) insertIndex = arr.length;
    
    // 3. 创建新数组并完成插入
    int[] newArr = new int[arr.length + 1];
    // i:新数组newArr的索引;j:原数组arr的索引
    for(int i=0, j=0; i < newArr.length; i++) {
        if(i != insertIndex) {
            newArr[i] = arr[j];
            j++;
        } else {
            newArr[i] = insertNum;
        }
    }
    
    // 4. 输出结果验证
    System.out.println("原数组:" + Arrays.toString(arr));
    System.out.println("插入元素 " + insertNum + " 后的新数组:" + Arrays.toString(newArr));
  5. 数组综合操作:随机生成 10 个整数(1-100)保存到数组,实现:

    • 倒序打印。
    • 求平均值。
    • 求最大值及下标。
    • 查找是否包含数字 8。
  6. 数组引用传递练习:写出以下代码的打印结果:

    java
    char[] arr1 = {'a','z','b','c'};
    char[] arr2 = arr1;
    arr1[2] = '韩';
    for (int i = 0; i < arr2.length; i++) {
        System.out.println(arr1[i] + "," + arr2[i]);
    }
    // 输出:
    // a,a
    // z,z
    // 韩,韩
    // c,c
  7. 写出冒泡排序的代码:基于冒泡排序案例,独立实现从小到大排序。